﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Xml;
using System.Linq;
using System.Xml.Serialization;
using System.Runtime.Serialization;
using BasicHttpSohu;
using System.Windows.Forms;
using WeiBeeCommon.DataTypes;

namespace WeiBeeCommon.Core
{
    public class WeiBeeSohu : IWeiBee
    {
        #region 发微博
        public string AddTwitter(string content)
        {
            string url = "http://api.t.sohu.com/statuses/update.xml";
            string postData = "status=" + content;// +"&clientip=127.0.0.1" + "&jing=&wei=";
            string response = OAuth.OAuthWebRequest(Method.POST, url, postData);
            return response;
        }

        public string AddPicture(string content, string picfilename)
        {
            // http://api.t.sohu.com/statuses/upload.xml
            string url = "http://api.t.sohu.com/statuses/upload.xml";
            string postData = "status=" + content;// +"&pic=" + picfilename;
            string response = OAuth.OAuthWebRequest(Method.POST, url, postData, picfilename);
            return response;
        }

        /// <summary>
        /// 根据ID转发一条微博
        /// </summary>
        /// <param name="id">微博ID</param>
        /// <param name="status">转发理由</param>
        /// <returns></returns>
        public string Retweet(string id, string status)
        {
            string url = string.Format(@"http://api.t.sohu.com/statuses/transmit/{0}.xml",id);
            status = (string.IsNullOrEmpty(status)) ? @"转发" : status;
            string para = string.Format("status={0}", status);
            return OAuth.OAuthWebRequest(Method.POST, url, para);
        }
        #endregion
        #region 数据获取
        public List<SohuStatus> PublicTimeline()
        {
            const string url = "http://api.t.sohu.com/statuses/public_timeline.xml";
            string response = OAuth.OAuthWebRequest(Method.GET, url, null);
            var xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(response);
            return GetPublicStatusList(xmlDoc);
        }
        private List<SohuStatus> GetPublicStatusList(XmlDocument doc)
        {
            XmlNodeList nodeList = doc.SelectNodes("/statuses/status");
            return GetStatusList(nodeList);
        }
        private List<SohuStatus> GetSearchStatusList(XmlDocument doc)
        {
            XmlNodeList nodeList = doc.SelectNodes("/searchResult/statuses/status");
            return GetStatusList(nodeList);
        }

        private List<SohuStatus> GetStatusList(XmlNodeList nodeList)
        {
            var statusList = new List<SohuStatus>();
            foreach (XmlNode node in nodeList)
            {
                SohuStatus status = new SohuStatus();
                status.CreatedAt = node.SelectSingleNode("created_at").InnerText; // To-do: change it to DateTime //  <created_at>Sun Jan 23 10:22:00 +0800 2011</created_at>
                status.Id = node.SelectSingleNode("id").InnerText;  //  <id>329043096</id>
                status.Text = node.SelectSingleNode("text").InnerText;//  <text>对 @曹颖 说：恭喜你呀 再给你拜个早年</text>
                status.Source = node.SelectSingleNode("source").InnerText;//  <source>搜狐微博</source>
                status.Favorited = bool.Parse(node.SelectSingleNode("favorited").InnerText);//  <favorited>false</favorited>
                if (string.IsNullOrEmpty(node.SelectSingleNode("truncated").InnerText))
                {
                    status.Truncated = false;
                }
                else
                {
                    status.Truncated = bool.Parse(node.SelectSingleNode("truncated").InnerText);//  <truncated>false</truncated>
                }
                status.InReplyToStatusId = node.SelectSingleNode("in_reply_to_status_id").InnerText;//  <in_reply_to_status_id/>
                status.InReplyToUserId = node.SelectSingleNode("in_reply_to_user_id").InnerText;//  <in_reply_to_user_id/>
                status.InReplyToScreenName = node.SelectSingleNode("in_reply_to_screen_name").InnerText;//  <in_reply_to_screen_name/>
                status.InReplyToStatusText = node.SelectSingleNode("in_reply_to_status_text").InnerText;//  <in_reply_to_status_text/>
                status.SmallPic = node.SelectSingleNode("small_pic").InnerText;//  <small_pic/>
                status.MiddlePic = node.SelectSingleNode("middle_pic").InnerText;//  <middle_pic/>
                status.OriginalPic = node.SelectSingleNode("original_pic").InnerText;//  <original_pic/>
                status.User = GetSohuUser(node.SelectSingleNode("user"));
                if (node.SelectSingleNode("coordinates") != null)
                {
                    status.Coordinates = node.SelectSingleNode("coordinates").InnerText;//  <coordinates/>
                }
                if (node.SelectSingleNode("in_reply_to_has_image") != null)
                {
                    status.inReplyToHasImage = bool.Parse(node.SelectSingleNode("in_reply_to_has_image").InnerText);//  <in_reply_to_has_image>false</in_reply_to_has_image>
                }
                statusList.Add(status);
            }
            return statusList;
        }

        private SohuUser GetSohuUser(XmlNode xmlNode)
        {
            SohuUser sohuUser = new SohuUser();
                //  <user>
            sohuUser.id = xmlNode.SelectSingleNode("id").InnerText;//    <id>35650585</id>
            sohuUser.ScreenName = xmlNode.SelectSingleNode("screen_name").InnerText;//    <screen_name>强的</screen_name>
            sohuUser.name = xmlNode.SelectSingleNode("name").InnerText; //    <name/>
            sohuUser.Location = xmlNode.SelectSingleNode("location").InnerText;//    <location>辽宁省,丹东市</location>
            sohuUser.Description = xmlNode.SelectSingleNode("description").InnerText;//    <description/>
            sohuUser.Url = xmlNode.SelectSingleNode("url").InnerText;//    <url/>
            sohuUser.ProfileImageUrl = xmlNode.SelectSingleNode("profile_image_url").InnerText; //    <profile_image_url>http://s5.cr.itc.cn/mblog/icon/62/be/m_12957060097331.jpg</profile_image_url>
            sohuUser.Protected = bool.Parse(xmlNode.SelectSingleNode("protected").InnerText);//    <protected>true</protected>
            sohuUser.FollowersCount = int.Parse(xmlNode.SelectSingleNode("followers_count").InnerText);//    <followers_count>4</followers_count>
            sohuUser.ProfileBackGroundColor = xmlNode.SelectSingleNode("profile_background_color").InnerText;//    <profile_background_color/>
            sohuUser.ProfileTextColor = xmlNode.SelectSingleNode("profile_text_color").InnerText;//    <profile_text_color/>
            sohuUser.ProfileLinkColor = xmlNode.SelectSingleNode("profile_link_color").InnerText;//    <profile_link_color/>
            sohuUser.ProfileSideBarFillColor = xmlNode.SelectSingleNode("profile_sidebar_fill_color").InnerText;//    <profile_sidebar_fill_color/>
            sohuUser.ProfileSideBarBorderColors = xmlNode.SelectSingleNode("profile_sidebar_border_color").InnerText;//    <profile_sidebar_border_color/>
            sohuUser.FriendsCount = int.Parse(xmlNode.SelectSingleNode("friends_count").InnerText);//    <friends_count>117</friends_count>
            sohuUser.CreatedAt = xmlNode.SelectSingleNode("created_at").InnerText;//    <created_at>Sat Jan 22 22:06:05 +0800 2011</created_at>
            sohuUser.FavouritesCount = int.Parse(xmlNode.SelectSingleNode("favourites_count").InnerText);//    <favourites_count>0</favourites_count>
            sohuUser.UtCOffset = xmlNode.SelectSingleNode("utc_offset").InnerText;//    <utc_offset/>
            sohuUser.TimeZone = xmlNode.SelectSingleNode("time_zone").InnerText;//    <time_zone/>
            sohuUser.ProfileBackgrounImageUrl = xmlNode.SelectSingleNode("profile_background_image_url").InnerText;//    <profile_background_image_url/>
            sohuUser.Notifications = xmlNode.SelectSingleNode("notifications").InnerText;//    <notifications/>
            sohuUser.GeoEnabled = bool.Parse(xmlNode.SelectSingleNode("geo_enabled").InnerText);//    <geo_enabled>false</geo_enabled>
            sohuUser.StatusesCount = int.Parse(xmlNode.SelectSingleNode("statuses_count").InnerText);//    <statuses_count>6</statuses_count>
            sohuUser.Following = bool.Parse(xmlNode.SelectSingleNode("following").InnerText);//    <following>false</following>
            sohuUser.Verified = bool.Parse(xmlNode.SelectSingleNode("verified").InnerText);//    <verified>false</verified>
            sohuUser.Lang = xmlNode.SelectSingleNode("lang").InnerText;//    <lang>zh_cn</lang>
            sohuUser.ContributorsEnabled = bool.Parse(xmlNode.SelectSingleNode("contributors_enabled").InnerText);//    <contributors_enabled>false</contributors_enabled>
            //  </user>
            return sohuUser;
        }
        #endregion
        #region 搜索接口
        public List<SohuStatus> SearchStatues(string q)
        {
            string url = "http://api.t.sohu.com/statuses/search.xml?rpp=20&q=" + q;// +"&since=" + timestamp5mintuesago;
            string response = OAuth.OAuthWebRequest(Method.GET, url, null);
            var xmlDocument = new XmlDocument();
            xmlDocument.LoadXml(response);
            return GetSearchStatusList(xmlDocument);
        }
        #endregion
        #region 社交网络
        public List<SohuUser> Followers()
        {
            return Followers(GetUserId());
        }
        public List<SohuUser> Followers(string userId)
        {
            string url = string.Format("http://api.t.sohu.com/statuses/followers/{0}.xml?count=20",userId);
            string response = OAuth.OAuthWebRequest(Method.GET, url, null);
            var xmlDocument = new XmlDocument();
            xmlDocument.LoadXml(response);
            return GetFollowerUserList(xmlDocument);
        }

        private List<SohuUser> GetFollowerUserList(XmlDocument xmlDocument)
        {
            XmlNodeList userNodeListWithLatestStatus = xmlDocument.SelectNodes("/users/user");
            return (from XmlNode userNodeWithStatus in userNodeListWithLatestStatus select GetSohuUser(userNodeWithStatus)).ToList();
        }
        #endregion
        #region VisitFromFollowers
        int _listSize = 211;
        Queue<string> _followersQueue;
        Queue<string> FollowersQueue
        {
            get
            {
                if (_followersQueue == null)
                {
                    _followersQueue = new Queue<string>();
                }
                return _followersQueue;
            }
        }
        public void VisitFromFollowers()
        {
            string userid = GetUserId();
            do
            {
                foreach (SohuUser myFollower in Followers(userid))
                {
                    if (!UserIdList.Contains(myFollower.id))
                    {
                        FollowersQueue.Enqueue(myFollower.id);
                        if (IsQualifiedUser(myFollower))
                        {
                            UserIdList.Add(myFollower.id);
                        }
                    }
                }
                userid = FollowersQueue.Dequeue();
            } while ( (FollowersQueue.Count > 0) && (UserIdList.Count < _listSize));

            _navigateIndex = 0;
            //DoNavigate();
        }
        #endregion


        /// <summary>
        /// Delete fridenships
        /// </summary>
        /// <param name="id">sohu user id</param>
        /// <returns></returns>
        public string DelFavor(string id)
        {
            string url = string.Format("http://api.t.sohu.com/friendships/destroy/{0}.xml", id);
            string parameters = string.Format("id={0}", id);
            string response = OAuth.OAuthWebRequest(Method.POST, url, parameters);
            XmlDocument xml = new XmlDocument();
            xml.LoadXml(response);
            HandleMaxAccessLimits(xml);
            return response;
        }

        public string TestXAuthLogin(string username, string password)
        {
            string url = "http://api.t.sohu.com/oauth/access_token";
            string postData = string.Format("x_auth_username={0}&x_auth_password={1}&x_auth_mode=client_auth", username, password);
            return OAuth.OAuthWebRequest(Method.POST, url, postData);
        }
        public List<Result> GetFriendTimelines()
        {
            string url = "http://api.t.sohu.com/statuses/friends_timeline.xml";
            string xml = OAuth.OAuthWebRequest(Method.GET,  url, string.Empty);

            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(xml);
            return GetStatusList(xmlDoc);
        }

        private List<Result> GetStatusList(XmlDocument xml)
        {
            var statusList = new List<Result>();

            foreach (XmlNode statusNode in xml.GetElementsByTagName("status"))
            {
                var statusInfo = new Result();
                string statusText = WebHelper.UrlDecode(statusNode["text"].InnerText);
                statusInfo.Text = statusText;
                statusInfo.ID = statusNode["id"].InnerText;
                statusInfo.CreatedAt = ConvertTwitterDate(statusNode["created_at"].InnerText);

                Result UserInfo = GetUserInfoFromNode(statusNode.SelectSingleNode("user"));
                statusInfo.ProfileImageUrl = UserInfo.ProfileImageUrl;

                statusList.Add(statusInfo);
            }

            return statusList;
        }
        private static string ConvertTwitterDate(string twitterDate)
        {
            string[] elements = twitterDate.Split(' ');

            string dayElement = Convert.ToInt32(elements[2]) == DateTime.Now.Day ? "Today" : elements[0];

            string timeElement = elements[3];
            timeElement = timeElement.Substring(0, timeElement.LastIndexOf(':'));

            return string.Concat(dayElement, " ", timeElement);
        }

        private static Result GetUserInfoFromNode(XmlNode userNode)
        {
            Result userInfo = new Result();

            // Get the user's latest status
            XmlNode userStatusNode = userNode.SelectSingleNode("status");

            // This info may not exist on all user nodes
            if (userStatusNode != null)
                userInfo.Text = userStatusNode["text"].InnerText;

            userInfo.ProfileImageUrl = userNode["profile_image_url"].InnerText;

            return userInfo;
        }

        #region BatchVisit
        private readonly string[] _popKeyword = {"转发", "大", "和", "不", "在", "一", "是","有","了","的"};
        public void BatchVisitMain()
        {
            var newlypostUserList = PublicTimeline();
            newlypostUserList.AddRange(SearchStatues(_popKeyword[DateTime.Now.Minute % 7]));

            foreach (var user in newlypostUserList)
            {
                // Don't visit visited users.
                if (!_visitedHelper.VisitedUserIdList.Contains(user.User.id) && !UserIdList.Contains(user.User.id) && IsQualifiedUser(user.User) )
                {
                    UserIdList.Add(user.User.id);
                }
            }
        }

        private bool IsValuedContent(string text)
        {
            return !string.IsNullOrEmpty(text);//text.Contains("欢乐送"));
        }

        private bool IsQualifiedUser(SohuUser sohuUser)
        {
            bool isQualified = sohuUser.Verified || (sohuUser.FriendsCount < 500 && sohuUser.FriendsCount > 5);
            //Don't visit my follower
            FavorUser favoreUserTrue = new FavorUser(int.Parse(sohuUser.id), true);
            FavorUser favoreUserFalse = new FavorUser(int.Parse(sohuUser.id), false);
            if (FavoreUserList.Contains(favoreUserTrue) || FavoreUserList.Contains(favoreUserFalse))
            {
                isQualified = false;
            }
            return isQualified;
        }

        private WebBrowser SohuWebBrowser
        {
            get
            {
                if (_webBrowser == null)
                {
                    _webBrowser = new WebBrowser();
                    _webBrowser.ScriptErrorsSuppressed = true;
                    _webBrowser.Navigated += WbNavigated;
                }
                return _webBrowser;
            }
        }
        private List<string> _userIdList;
        private List<string> UserIdList
        {
            get
            {
                if (_userIdList == null)
                {
                    _userIdList = new List<string>();
                }
                return _userIdList;
            }
        }
        public bool IsUserIdListReady 
        { 
            get
            {
                return UserIdList.Count >= _listSize;
            }
        }

        private WebBrowser _webBrowser;
        const string Urlformater = "http://t.sohu.com/u/{0}";
        public void DoNavigate()
        {
            if (UserIdList.Count > 0)
            {
                Thread.Sleep(1000);
                SohuWebBrowser.Navigate(string.Format(Urlformater, UserIdList[_navigateIndex]));
            }
        }

        private int _navigateIndex;
        VisitedHelper _visitedHelper = new VisitedHelper("visited.xml");
        void WbNavigated(object sender, WebBrowserNavigatedEventArgs e)
        {
            _navigateIndex++;
            if(_navigateIndex<UserIdList.Count)
            {
                DoNavigate();
            }
            else if (_navigateIndex == UserIdList.Count)
            {
                // Save it to the long list and save the long list to file
                _visitedHelper.AppendToVisited(UserIdList);
                UserIdList.Clear();
                _navigateIndex = 0;
            }
        }

        public bool IsNavigating
        {
            get
            {
                return _navigateIndex != 0;
            }
        }

        #endregion BatchVisit
        #region BatchAddFavors
        /// <summary>
        /// Add friendships
        /// </summary>
        /// <param name="id">sohu user id</param>
        /// <returns></returns>
        public string AddFavor(string id)
        {
            // http://api.t.sohu.com/friendships/create/23432.xml
            string url = string.Format("http://api.t.sohu.com/friendships/create/{0}.xml", id);
            string parameters = string.Format("id={0}", id);
            string response = OAuth.OAuthWebRequest(Method.POST, url, parameters);
            XmlDocument xml = new XmlDocument();
            xml.LoadXml(response);
            HandleMaxAccessLimits(xml);
            return response;
        }

        /// <summary>
        /// 实例http://api.t.sohu.com/statuses/friends/11104.xml
        /// 或http://api.t.sohu.com/statuses/friends.xml
        /// </summary>
        /// <param name="id">sohu user id</param>
        /// <param name="cursorID"></param>
        /// <returns></returns>
        public string GetFanslist(string id, ref string cursorID)
        {
            string parameters;
            if(string.IsNullOrEmpty(id))
            {
                parameters = ".xml";
            }
            else
            {
                parameters = string.Format("/{0}.xml", id);
            }
            parameters += "?cursor=" + cursorID + "&count=20";
            string url = "http://api.t.sohu.com/statuses/friends" + parameters;
            string response = OAuth.OAuthWebRequest(Method.GET, url, null);
            var xml = new XmlDocument();
            xml.LoadXml(response);
            HandleMaxAccessLimits(xml);
            if (xml.GetElementsByTagName("cursor_id").Count > 0)
            {
                cursorID = xml.GetElementsByTagName("cursor_id")[0].InnerText;
            }
            else
            {
                cursorID = "-1";
            }
            return response;
        }

        public List<User> GetUser(string xml)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xml);
            XmlNodeList list = doc.SelectNodes("/result/users/user");
            List<User> lstUser = new List<User>();
            foreach (XmlNode node in list)
            {
                User user = new User();
                user.id = node.SelectSingleNode("id").InnerText;
                user.screen_name = node.SelectSingleNode("screen_name").InnerText;
                user.name = node.SelectSingleNode("name").InnerText;
                user.location = node.SelectSingleNode("location").InnerText;
                user.description = node.SelectSingleNode("description").InnerText;
                user.url = node.SelectSingleNode("url").InnerText;
                user.profile_image_url = node.SelectSingleNode("profile_image_url").InnerText;
                user._protected = bool.Parse(node.SelectSingleNode("protected").InnerText);
                user.followers_count = node.SelectSingleNode("followers_count").InnerText;
                user.friends_count = node.SelectSingleNode("friends_count").InnerText;
                user.favourites_count = node.SelectSingleNode("favourites_count").InnerText;
                user.statuses_count = node.SelectSingleNode("statuses_count").InnerText;
                user.following = bool.Parse(node.SelectSingleNode("following").InnerText);
                user.verified = bool.Parse(node.SelectSingleNode("verified").InnerText);
                user.contributors_enabled = bool.Parse(node.SelectSingleNode("contributors_enabled").InnerText);
                lstUser.Add(user);
            }
            return lstUser;
        }

        private void HandleMaxAccessLimits(XmlDocument xml)
        {
            //DateTime till = this.GetRestSeconds();
            if (xml.GetElementsByTagName("error").Count > 0)
            {
                if (string.Compare(
                    xml.GetElementsByTagName("error")[0].InnerText,
                    "Reached max access time per hour.") == 0)
                {
                    Console.WriteLine("Reached max access time per hour.");
                    throw new ExceedMaximumAccessException();
                }

            }
        }
        public string GetFanslist(string id)
        {
            string cursorID = "-1";
            return GetFanslist(id, ref cursorID);
        }
        public string GetFanslist()
        {
            return GetFanslist(string.Empty);
        }

        public bool AddFavorFromFansList(string id)
        {
            if (string.Compare(id, GetUserId(), true) == 0)
            {
                id = FavoreUserList[_dequeueIndex].Uid.ToString();
            }
            FavoreUserList[_dequeueIndex].Favored = true;
            TryAddFavor(id);
            string cursor = "-1";
            do
            {
                string fanslist = GetFanslist(id, ref cursor);
                var xmlDocument = new XmlDocument();
                xmlDocument.LoadXml(fanslist);
                HandleMaxAccessLimits(xmlDocument);
                foreach (XmlNode user in xmlDocument.GetElementsByTagName("user"))
                {
                    QueueToList(user.FirstChild.InnerText);
                }
            } while (Int32.Parse(cursor) != -1);
            SaveFavoredList();
            while (_dequeueIndex < FavoreUserList.Count && FavoreUserList[_dequeueIndex].Favored)
            {
                _dequeueIndex++;
            }
            if (_dequeueIndex >= FavoreUserList.Count) return true;
            return AddFavorFromFansList(FavoreUserList[_dequeueIndex].Uid.ToString());
        }

        private void QueueToList(string idstring)
        {
            if (!IsInFavorList(idstring))
            {
                FavoreUserList.Add(new FavorUser(int.Parse(idstring), false));
                TryAddFavor(idstring);
            }
        }
        private bool IsInFavorList(string idstring)
        {
            FavorUser fuTrue = new FavorUser(int.Parse(idstring), true);
            FavorUser fuFalse = new FavorUser(int.Parse(idstring), false);
            return FavoreUserList.Contains(fuTrue) || FavoreUserList.Contains(fuFalse);
        }

        private void TryAddFavor(string id)
        {
            if (!IsFavored(id))
            {
                try
                {
                    AddFavor(id);
                    FavoreUserList.Add(new FavorUser(Int32.Parse(id), false));
                    SaveFavoredList();
                }
                catch (System.Net.WebException alreadyFavoredException)
                {
                    Console.WriteLine("user:" + id + " has already be your favor." + alreadyFavoredException.Message);
                }
            }
            return;
        }
        /// <summary>
        /// Try the best to destory friends to a very lower count
        /// </summary>
        public void BatchDestoryFriends()
        {
            Hash hash = RateLimitStatus();
            int callCounts = 0;
            List<User> lstUser = new List<User>();
            string cursor = "-1";
            do
            {
                callCounts++;
                string fanslist = GetFanslist(GetUserId(), ref cursor);
                lstUser.AddRange(GetUser(fanslist));
            } while (string.Compare("-1", cursor) != 0);
            lstUser.Sort(new UserComparer());
            for (int i = 0; i < (hash.remaining_hits - callCounts) & i < lstUser.Count - 50; i++)
            {
                DelFavor(lstUser[i].id);
            }
        }

        #region FavoreUserListData
        private List<FavorUser> _favoreUserList = new List<FavorUser>();
        public List<FavorUser> FavoreUserList
        {
            get 
            {
                if (_favoreUserList.Count == 0)
                {
                    LoadFavoredListFromFile();
                    if (_favoreUserList.Count == 0)
                    {
                        string fanslist = GetFanslist(GetUserId());
                        var xmlDocument = new XmlDocument();
                        xmlDocument.LoadXml(fanslist);
                        HandleMaxAccessLimits(xmlDocument);
                        foreach (XmlNode user in xmlDocument.GetElementsByTagName("user"))
                        {
                            _favoreUserList.Add(new FavorUser(int.Parse(user.FirstChild.InnerText), false));
                        }
                    }
                }
                
                return _favoreUserList; 
            }
        }
        private int _dequeueIndex;
        /// <summary>
        ///ReteLimitStatus 的摘要说明
        /// </summary>
        public class Hash
        {
            public int hourly_limit;
            public int remaining_hits;
            public long reset_time_in_seconds;
            public DateTime reset_time;
        }
        #endregion FavoreUserLiastData

        public void SaveFavoredList()
        {
            // New FavorUser type list
            string filename1 = string.Format("favorlist{0}.xml", this.GetUserId());
            XmlSerializer ser1 = new XmlSerializer(typeof(List<FavorUser>));
            using (FileStream fs1 = new FileStream(filename1, FileMode.Create, FileAccess.Write))
            {
                ser1.Serialize(fs1, _favoreUserList);
            }
        }

        public void LoadFavoredListFromFile()
        {
            string filename = string.Format("favorlist{0}.xml",this.GetUserId());
            if (!File.Exists(filename)) return;
            XmlSerializer ser = new XmlSerializer(typeof(List<FavorUser>));
            using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
            {
                try
                {
                    _favoreUserList = ser.Deserialize(fs) as List<FavorUser>;
                }
                catch
                {
                }
            }
            // Find first false user
            if (_favoreUserList != null)
                foreach (FavorUser fu in _favoreUserList)
                {
                    if (fu.Favored == false)
                    {
                        _dequeueIndex = _favoreUserList.IndexOf(fu);
                        break;
                    }
                }
        }

        public bool IsFavored(string id)
        {
            if (_favoreUserList.Count == 0)
            {
                LoadFavoredListFromFile();
                SaveFavoredList();
            }
            if (_favoreUserList.Count == 0) return false;
            if (string.Compare(id, GetUserId()) == 0) return true;
            return IsInFavorList(id);
        }

        private string _userId = string.Empty;
        /// <summary>
        /// Get My Sohu User Id
        /// </summary>
        /// <returns>My User Id</returns>
        public string GetUserId()
        {
            if (string.IsNullOrEmpty(_userId))
            {
                string url = "http://api.t.sohu.com/users/show.xml";
                string response = OAuth.OAuthWebRequest(Method.GET, url, null);
                XmlDocument xml = new XmlDocument();
                xml.LoadXml(response);
                HandleMaxAccessLimits(xml);
                if (xml.GetElementsByTagName("id").Count > 0)
                {
                    _userId = xml.GetElementsByTagName("id")[0].InnerText;
                }
            }
            return _userId;
        }
        #endregion

        /// <summary>
        /// 获取访问上限信息
        /// </summary>
        /// <returns></returns>
        public Hash RateLimitStatus()
        {
            string url = "http://api.t.sohu.com/account/rate_limit_status.xml";
            string xml = OAuth.OAuthWebRequest(Method.GET, url, null);
            if (xml.Contains("<error>"))
                throw new Exception("获取访问上限失败！");
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xml);
            Hash hash = new Hash();
            hash.remaining_hits = Convert.ToInt32(doc.SelectSingleNode("/hash/remaining-hits").InnerText);
            hash.hourly_limit = Convert.ToInt32(doc.SelectSingleNode("/hash/hourly-limit").InnerText);
            hash.reset_time_in_seconds = Convert.ToInt32(doc.SelectSingleNode("/hash/reset-time-in-seconds").InnerText);

            string sdt = doc.SelectSingleNode("/hash/reset-time").InnerText;
            if (!string.IsNullOrEmpty(sdt))
            {
                string[] sdtArr = sdt.Split(' ');
                string newDt = string.Format("{0}, {1} {2} {3} {4}", sdtArr[0], sdtArr[2], sdtArr[1], sdtArr[5], sdtArr[3]);
                hash.reset_time = DateTime.Parse(newDt);
            }
            return hash;
        }
        private DateTime _restDateTime = DateTime.Now;
        public DateTime RestDateTime 
        { 
            get
            {
                if (_restDateTime < DateTime.Now)
                {
                    const string url = "http://api.t.sohu.com/account/rate_limit_status.xml";
                    string response = OAuth.OAuthWebRequest(Method.GET, url, null);
                    var xml = new XmlDocument();
                    xml.LoadXml(response);
                    var dtBase = new DateTime(1970, 1, 1, 8, 0, 0);
                    long resttimeseconds;
                    if (xml.GetElementsByTagName("reset-time-in-seconds").Count > 0)
                    {
                        string resttimeinsecondsString = xml.GetElementsByTagName("reset-time-in-seconds")[0].InnerText;
                        resttimeseconds = long.Parse(resttimeinsecondsString);
                        _restDateTime = dtBase.AddSeconds(resttimeseconds);
                    }
                    else
                    {
                        _restDateTime = DateTime.Now.AddMinutes(2);
                    }
                }
                return _restDateTime;
            }
            set
            {
                _restDateTime = value;
            }
        }
        public OAuthSohu OAuth { get; set; }

        public bool IsEnabled
        {
            get
            {
                return !string.IsNullOrEmpty(OAuth.Token);
            }
        }

        protected Random RandomGenerator = new Random();
        public WeiBeeSohu()
        {
            if (OAuth == null)
            {
                OAuth = new OAuthSohu();
                _listSize = RandomGenerator.Next(11, 220);
            }
        }

        public void SetOAuth(string token, string secret)
        {
            OAuth.Token = token;
            OAuth.TokenSecret = secret;
        }

        #region IWeiBee Members


        public WeiBeeType UserType
        {
            get { return WeiBeeType.Sohu; }
        }

        public OAuthBase GetOAuth()
        {
            return OAuth;
        }

        public UserBase GetWeiBeeUser()
        {
            string url = "http://api.t.sohu.com/users/show.xml";
            string response = OAuth.OAuthWebRequest(Method.GET, url, null);
            return Utility.StringToWeiBeeTypeSohu(response);
        }

        public DateTime GetResetTime()
        {
            return DateTime.Now.AddHours(1);
        }

        public int GetTotalRetweetHourlyLimitNumber()
        {
            return 200;
        }

        public int GetRetweetIntervalNumber()
        {
            return 13;
        }
        #endregion
    }
    #region CustomException
    public class ExceedMaximumAccessException : System.Net.WebException
    {
    }
    #endregion CustomException
    #region SerilazableTypes
    public class FavorUser : ISerializable 
    {
        public FavorUser() { Uid = 0; Favored = false; }
        public FavorUser(int uid, bool favored)
        {
            Uid = uid;
            Favored = favored;
        }
        public int Uid { get; set; }
        public bool Favored { get; set; }

        #region ISerializable Members
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("Uid", Uid);
            info.AddValue("Favored", Favored);
        }
        #endregion
    }
    #endregion
}
